﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;

#if ENABLE_MONO

//Unity Editor 環境 用 MonoBridge 和 c++ 通訊
partial class MonoBridge : IBridge
{
    IntPtr libHandle;
    delegate void deleMonoInit(IntPtr functGetBridge, ILBridge.EnvTag EnvTag);
    delegate void deleMonoEvent(Int64 msgid, Int64 p1, IntPtr p2);
    delegate void deleMonoUpdate(float totaltime, float deltatime);
    deleMonoInit funcMonoInit_Cpp;
    deleMonoEvent funcMonoEvent_Cpp;
    deleMonoUpdate funcMonoUpdate_Cpp;

    static Dictionary<string, IntPtr> exportMonoMethods = null;
    static IntPtr exportGetBridgeFunc;
    public bool CPPDLL_Load(string dllname)
    {
        ILBridge.Log("MonoBridge::CPPDLL_Load.");

#if UNITY_EDITOR
        //编辑器模式，会自动Free 加载的CPP模块
        UnityEditor.EditorApplication.playModeStateChanged += (s) =>
          {
              if (s == UnityEditor.PlayModeStateChange.ExitingPlayMode)
              {
                  UnityEngine.Debug.LogWarning("close editor.");
                  CPPDLL_Free();
              }
          };
#endif
        if (libHandle != IntPtr.Zero)
        {
            ILBridge.Log("::already init MonoBridge");
            return false;
        }

        //将c#的函数指针准备好,c++通过GetBridge方法获取接口
        if (exportGetBridgeFunc == IntPtr.Zero)
        {

            Func<IntPtr, IntPtr> _Mono_GetBridgeFunc_Unsafe = Mono_GetBridgeFunc;
            exportGetBridgeFunc = Marshal.GetFunctionPointerForDelegate(_Mono_GetBridgeFunc_Unsafe);

            exportMonoMethods = new Dictionary<string, IntPtr>();
            //准备接口

            //Test 接口
            Action _Mono_Test_Unsafe = Export_TestFunc;
            exportMonoMethods["test_call"] = Marshal.GetFunctionPointerForDelegate(_Mono_Test_Unsafe);
            //Action<IntPtr> _Mono_TestObj_Unsafe = Export_TestFunc_Obj;
            //exportMonoMethods["test_dumpobj"] = Marshal.GetFunctionPointerForDelegate(_Mono_TestObj_Unsafe);
            //Action<IntPtr> _Mono_TestType_Unsafe = Export_TestFunc_Type;
            //exportMonoMethods["test_dumptype"] = Marshal.GetFunctionPointerForDelegate(_Mono_TestType_Unsafe);


            {
                Action<IntPtr, Int32> _Mono_LogString = Export_LogString;
                exportMonoMethods["test_logstring"] = Marshal.GetFunctionPointerForDelegate(_Mono_LogString);
            }
        }

        try
        {
            libHandle = libShell.LoadModule(dllname);
        }
        catch(Exception err)
        {
            ILBridge.Log("loadlib Error=" + err.Message);
        }
        ILBridge.Log("loadlib=" + libHandle.ToString("X16"));
        if (libHandle == IntPtr.Zero)
        {
            var str = libShell.GetLoadModuleError();
            ILBridge.Log("loaderror:" + str);
            return false;
        }
        IntPtr funchandleInit = libShell.GetSymbol(libHandle, "cpp_Init");
        IntPtr funchandleEvent = libShell.GetSymbol(libHandle, "cpp_Event");
        IntPtr funchandleUpdate = libShell.GetSymbol(libHandle, "cpp_Update");
        ILBridge.Log("funchandleInit=" + funchandleInit.ToString("X16"));
        ILBridge.Log("funchandleEvent=" + funchandleEvent.ToString("X16"));
        ILBridge.Log("funchandleUpdate=" + funchandleUpdate.ToString("X16"));

        funcMonoInit_Cpp = (deleMonoInit)Marshal.GetDelegateForFunctionPointer(funchandleInit, typeof(deleMonoInit));
        funcMonoEvent_Cpp = (deleMonoEvent)Marshal.GetDelegateForFunctionPointer(funchandleEvent, typeof(deleMonoEvent));
        funcMonoUpdate_Cpp = (deleMonoUpdate)Marshal.GetDelegateForFunctionPointer(funchandleUpdate, typeof(deleMonoUpdate));


        try
        {
            funcMonoInit_Cpp(exportGetBridgeFunc, ILBridge.EnvTag.MONO);
        }
        catch (Exception err)
        {
            ILBridge.Log("CPPDLL_Event Error" + err.Message);
        }
        return true;
    }
    public void CPPDLL_Event(Int64 msgid, Int64 param1, IntPtr param2)
    {
        try
        {
            if (libHandle != IntPtr.Zero)
            {
                funcMonoEvent_Cpp(msgid, param1, param2);
            }
        }
        catch (Exception err)
        {
            ILBridge.Log("CPPDLL_Event Error" + err.Message);
        }
    }

    public void CPPDLL_CallUpdate()
    {
        try
        {
            if (libHandle != IntPtr.Zero)
            {
                funcMonoUpdate_Cpp(UnityEngine.Time.time, UnityEngine.Time.deltaTime);
            }
        }
        catch (Exception err)
        {
            ILBridge.Log("CPPDLL_Event Error" + err.Message);
        }
    }
    public void CPPDLL_Free()
    {
        if (libHandle != IntPtr.Zero)
        {
            libShell.FreeModule(libHandle);
            libHandle = IntPtr.Zero;
            funcMonoInit_Cpp = null;
            funcMonoEvent_Cpp = null;
            funcMonoUpdate_Cpp = null;
        }
    }
    static IntPtr Mono_GetBridgeFunc(IntPtr unsafeCharPtr)
    {
        string name = Marshal.PtrToStringAnsi(unsafeCharPtr);

        var il2cppname = name.Replace("il2cpp", "mono");

        IntPtr handle = libShell.GetSymbol(libShell.GetRuntimeModule(), il2cppname);
        if (name.Contains("call"))
        {
            ILBridge.Log("callmethod:" + name + " " + handle.ToString("X16"));
        }
        if (handle != IntPtr.Zero)
        {
            UnityEngine.Debug.Log("GetSymbol got:" + name);
            return handle;
        }
        else if(exportMonoMethods.ContainsKey(name))
        {
            UnityEngine.Debug.LogWarning("GetSymbol got fake:" + name);

            return exportMonoMethods[name];
        }
        else 
        {
            UnityEngine.Debug.LogError("GetSymbol got Null:" + name);

            return IntPtr.Zero;
        }
    }
    static void Export_LogString(IntPtr unsafeCharPtr, int level)
    {
        string str = Marshal.PtrToStringAnsi(unsafeCharPtr);
        ILBridge.Log(str, (ILBridge.LogLevel)level);
    }

    static void Export_TestFunc()
    {
        //native wrap 的两端是隔离的,所有的Export内部应该有try，防止把错误传递到Native
        try
        {
            ILBridge.Log("Mono_TestFunc. call from cpp");
        }
        catch (Exception err)
        {
            //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
            UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
        }
    }
    //static void Export_TestFunc_Obj(IntPtr handle)
    //{
    //    try
    //    {
    //        UnityEngine.Debug.LogWarning("Mono_TestFunc_Obj.");
    //        var h = GCHandle.FromIntPtr(handle);
    //        UnityEngine.Debug.LogWarning(h.Target);
    //        if (h.Target != null)
    //        {
    //            UnityEngine.Debug.LogWarning(h.Target.GetType());
    //        }
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}
    //static void Export_TestFunc_Type(IntPtr handle)
    //{
    //    try
    //    {
    //        UnityEngine.Debug.LogWarning("Mono_TestFunc_Type.");
    //        if (handle == IntPtr.Zero || !allTypes.ContainsKey(handle))
    //        {
    //            UnityEngine.Debug.LogWarning("No type");
    //        }
    //        else
    //        {
    //            var t = allTypes[handle];
    //            UnityEngine.Debug.LogWarning(t);
    //        }
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}
    //static System.IntPtr Export_GetType(IntPtr _strNamespace, IntPtr _strType)
    //{
    //    try
    //    {
    //        UnityEngine.Debug.LogWarning("Mono_GetType_Unsafe.");
    //        var __namespace = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(_strNamespace);
    //        var __type = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(_strType);
    //        var sname = string.IsNullOrEmpty(__namespace) ? __type : (__namespace + "." + __type);
    //        Type t = _FindType(sname);
    //        if (t != null)
    //        {
    //            return _GetHandleFromType(t);
    //        }
    //        else
    //        {
    //            return IntPtr.Zero;
    //        }
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static System.IntPtr Export_GetFunction(IntPtr _strName)
    //{

    //    try
    //    {
    //        UnityEngine.Debug.LogWarning("Mono_GetFunction_Unsafe.");
    //        var __fullname = Marshal.PtrToStringAnsi(_strName);
    //        {
    //            if (allfuncs.ContainsKey(__fullname))
    //                return allfuncs[__fullname].delePtr;
    //            var __names = __fullname.Split(new string[] { "::" }, StringSplitOptions.None);
    //            var __type = _FindType("GetSymbol fake" + __names[0]);
    //            UnityEngine.Debug.Log(__type);
    //            var method = _FindMethod(__type, __names[1]);
    //            return _FindMethodDeleUnsafe(__type, __names[1]);
    //        }
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static void Export_GCHandle_Free(IntPtr handle)
    //{
    //    try
    //    {
    //        UnityEngine.Debug.LogWarning("Mono_GCHandleFree_Unsafe.");
    //        GCHandle.FromIntPtr(handle).Free();
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}
    //static IntPtr Export_Type_GetField_Get(IntPtr typeHandle, IntPtr unsafeCharStar)
    //{
    //    try
    //    {
    //        Type t = allTypes[typeHandle];
    //        string str = Marshal.PtrToStringAnsi(unsafeCharStar);

    //        var field = t.GetField(str);
    //        string fullname = t.FullName + "::" + str + "|get";
    //        if (allfuncs.ContainsKey(fullname))
    //        {
    //            return allfuncs[fullname].delePtr;
    //        }
    //        if (field == null)
    //        {
    //            return IntPtr.Zero;
    //        }

    //        var type = Type.GetType("DelegateProxy_Field_Get`1");
    //        var treal = type.MakeGenericType(new Type[] { field.FieldType });

    //        var trealctor = treal.GetConstructor(new Type[] { typeof(FieldInfo) });
    //        var deleProxy = trealctor.Invoke(new object[] { field }) as IDeleProxy;
    //        allfuncs[fullname] = deleProxy;
    //        return deleProxy.delePtr;
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_Type_GetField_Set(IntPtr typeHandle, IntPtr unsafeCharStar)
    //{
    //    try
    //    {
    //        Type t = allTypes[typeHandle];
    //        string str = Marshal.PtrToStringAnsi(unsafeCharStar);

    //        var field = t.GetField(str);
    //        string fullname = t.FullName + "::" + str + "|set";
    //        if (allfuncs.ContainsKey(fullname))
    //        {
    //            return allfuncs[fullname].delePtr;
    //        }
    //        if (field == null)
    //        {
    //            return IntPtr.Zero;
    //        }

    //        var type = Type.GetType("DelegateProxy_Field_Set`1");
    //        var treal = type.MakeGenericType(new Type[] { field.FieldType });

    //        var trealctor = treal.GetConstructor(new Type[] { typeof(FieldInfo) });
    //        var deleProxy = trealctor.Invoke(new object[] { field }) as IDeleProxy;
    //        allfuncs[fullname] = deleProxy;
    //        return deleProxy.delePtr;
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_Type_GetMethod(IntPtr typeHandle, IntPtr unsafeCharStar)
    //{
    //    try
    //    {
    //        var __type = allTypes[typeHandle];
    //        var __name = Marshal.PtrToStringAnsi(unsafeCharStar);
    //        return _FindMethodDeleUnsafe(__type, __name);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_Type_GetConstructor(IntPtr typeHandle, IntPtr unsafeCharStar)
    //{
    //    try
    //    {
    //        var __type = allTypes[typeHandle];
    //        var __name = Marshal.PtrToStringAnsi(unsafeCharStar);
    //        return _FindCTORDeleUnsafe(__type, __name);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_Object_New(IntPtr typeHandle)
    //{
    //    try
    //    {
    //        Type t = allTypes[typeHandle];
    //        var ctor = t.GetConstructor(new Type[] { });
    //        if (ctor == null)
    //            return IntPtr.Zero;
    //        var obj = ctor.Invoke(new object[] { });
    //        return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_String_FromCharPtr(IntPtr unsafeCharStar)
    //{
    //    try
    //    {
    //        string str = Marshal.PtrToStringAnsi(unsafeCharStar);
    //        return GCHandle.ToIntPtr(GCHandle.Alloc(str));
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_String_FromChar16Ptr(IntPtr unsafeChar16Star)
    //{
    //    try
    //    {
    //        string str = Marshal.PtrToStringUni(unsafeChar16Star);
    //        return GCHandle.ToIntPtr(GCHandle.Alloc(str));
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_String_ToCharPtr(IntPtr strHandle)
    //{
    //    try
    //    {
    //        var str = GCHandle.FromIntPtr(strHandle).Target as string;
    //        return Marshal.StringToHGlobalAnsi(str);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static void Export_String_ToCharPtr_Fix(IntPtr strHandle, IntPtr memtarget, int size)
    //{
    //    try
    //    {
    //        var str = GCHandle.FromIntPtr(strHandle).Target as string;
    //        IntPtr mem = Marshal.StringToHGlobalAnsi(str);
    //        unsafe
    //        {
    //            byte* src = (byte*)mem.ToPointer();
    //            byte* dest = (byte*)memtarget.ToPointer();
    //            dest[size - 1] = 0;
    //            for (var i = 0; i < size; i++)
    //            {
    //                dest[i] = src[i];
    //                if (src[i] == 0)
    //                    break;
    //            }
    //        }
    //        Marshal.FreeHGlobal(mem);

    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}
    //static IntPtr Export_String_ToChar16Ptr(IntPtr strHandle)
    //{
    //    try
    //    {
    //        var str = GCHandle.FromIntPtr(strHandle).Target as string;
    //        return Marshal.StringToHGlobalUni(str);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static void Export_String_ToChar16Ptr_Fix(IntPtr strHandle, IntPtr memtarget, int size)
    //{
    //    try
    //    {
    //        var str = GCHandle.FromIntPtr(strHandle).Target as string;
    //        IntPtr mem = Marshal.StringToHGlobalUni(str);
    //        unsafe
    //        {
    //            UInt16* src = (UInt16*)mem.ToPointer();
    //            UInt16* dest = (UInt16*)memtarget.ToPointer();
    //            dest[size - 1] = 0;
    //            for (var i = 0; i < size - 1; i++)
    //            {
    //                dest[i] = src[i];
    //                if (src[i] == 0)
    //                    break;
    //            }
    //        }
    //        Marshal.FreeHGlobal(mem);

    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}


    //static IntPtr Export_Struct_FromPtr(IntPtr typeHandle, IntPtr memaddr)
    //{
    //    try
    //    {
    //        Type t = allTypes[typeHandle];
    //        var obj = Marshal.PtrToStructure(memaddr, t);
    //        return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}
    //static IntPtr Export_Struct_ToPtr(IntPtr objHandle)
    //{
    //    try
    //    {
    //        var obj = GCHandle.FromIntPtr(objHandle).Target;
    //        int objsize = Marshal.SizeOf(obj);
    //        IntPtr mem = Marshal.AllocHGlobal(objsize);
    //        Marshal.StructureToPtr(obj, mem, false);
    //        return mem;
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return IntPtr.Zero;
    //    }
    //}

    //static int Export_Struct_SizeByType(IntPtr typeHandle)
    //{
    //    try
    //    {
    //        Type t = allTypes[typeHandle];
    //        return Marshal.SizeOf(t);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return 0;
    //    }
    //}
    //static int Export_Struct_SizeByObj(IntPtr objHandle)
    //{
    //    try
    //    {
    //        var obj = GCHandle.FromIntPtr(objHandle).Target;
    //        return Marshal.SizeOf(obj);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //        return 0;
    //    }
    //}
    //static void Export_Struct_ToPtr_Fix(IntPtr objHandle, IntPtr mem, int size)
    //{
    //    try
    //    {
    //        var obj = GCHandle.FromIntPtr(objHandle).Target;
    //        int objsize = Marshal.SizeOf(obj);
    //        if (size < objsize)
    //        {
    //            throw new Exception("error struct size");
    //        }
    //        Marshal.StructureToPtr(obj, mem, false);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}
    //static void Export_FreePtr(IntPtr ptr)
    //{
    //    try
    //    {
    //        Marshal.FreeHGlobal(ptr);
    //    }
    //    catch (Exception err)
    //    {
    //        //这里err.StackTrace无法穿透NativeWrap,但是Log本身的调用记录可以
    //        UnityEngine.Debug.LogError(err.Message + "|" + err.StackTrace + "|");
    //    }
    //}


}

#endif